#pragma once

#include <string>
#include <random>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <iomanip>
#include <sstream>

namespace suye 
{
class PassworldHasher  
{
public:
    // 生成随机盐值
    static std::string generateSalt(size_t length = 16) 
    {   
        const char charset[] = 
            "0123456789"
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz"; 
        
            std::random_device rd;
            std::mt19937 gen(rd());
            std::uniform_int_distribution<> dis(0, sizeof(charset) - 2);

            std::string salt;
            salt.reserve(length);
            for (size_t i = 0; i < length; ++i) {
                salt += charset[dis(gen)];
            }
            return salt;
    }

    // 使用PBKDF2加密密码
    static std::string hashPassword(const std::string& password, 
                                    const std::string& salt,
                                    int iterations = 10000)
    {
        uint8_t hash[SHA256_DIGEST_LENGTH];
        
        PKCS5_PBKDF2_HMAC(
            password.c_str(), 
            password.length(),
            (unsigned char*)salt.c_str(), 
            salt.length(),
            iterations, 
            EVP_sha256(),
            SHA256_DIGEST_LENGTH, 
            hash
        );

        // 转换为十六进制字符串
        std::stringstream ss;
        ss << std::hex << std::setfill('0');
        for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
            ss << std::hex << std::setw(2) << std::setfill('0') 
               << (int)hash[i];
        }

        return ss.str();
    }

    // 组合盐值和哈希值（存储格式：salt$hash）
    static std::string encryptPassword(const std::string& password) {
        std::string salt = generateSalt();
        std::string hash = hashPassword(password, salt);
        return salt + "$" + hash;
    }

    // 验证密码
    static bool verifyPassword(const std::string& password, 
                            const std::string& stored_hash) 
    {
        // 分离盐值和哈希值
        size_t pos = stored_hash.find('$');
        if (pos == std::string::npos) {
            return false;
        }

        std::string salt = stored_hash.substr(0, pos);
        std::string hash = stored_hash.substr(pos + 1);

        // 使用相同盐值计算密码哈希
        std::string computed_hash = hashPassword(password, salt);
        
        // 常量时间比较，防止时间攻击
        return constantTimeCompare(hash, computed_hash);
    }

private:
    // 常量时间字符串比较
    static bool constantTimeCompare(const std::string& a, const std::string& b) 
    {
        if (a.length() != b.length()) {
            return false;
        }

        unsigned char result = 0;
        for (size_t i = 0; i < a.length(); ++i) {
            result |= a[i] ^ b[i];
        }
        return result == 0;
    }
};
}
